#include "srv_dino_game.h"
#include "srv_dino_font.h"
#include "srv_lcd.h"
#include "drv_lcd_init.h"
#include "bsp_delay.h"
#include "srv_spi_flash.h"

#include "stdint.h"
#include "stdio.h"
#include "stdlib.h"

#define SCORE_NUM   8    //最后一位记录最高成绩,第一位为最新成绩
#define RECORD_ADDR   0x00

static uint8_t score_records[SCORE_NUM] = {0};

static void _ScoreReacord(uint8_t _score_num)
{
    spi_flash_erase_sector(RECORD_ADDR);
    spi_flash_write_no_check(RECORD_ADDR, score_records, _score_num);
}

static void _ScoreRead(uint8_t _score_num)
{
    spi_flash_read(RECORD_ADDR, score_records, _score_num);
}

static void _AddNewScore(uint8_t new_score)
{
    _ScoreRead(SCORE_NUM);
    for(uint8_t i=SCORE_NUM-2; i>0; i--)
    {
        score_records[i] = score_records[i-1];
    }
    score_records[0] = new_score;
    if(new_score > score_records[SCORE_NUM-1]){
        score_records[SCORE_NUM-1] = new_score;
    }
    
    _ScoreReacord(SCORE_NUM);
}



static void _DrawGround(void)
{
    const uint8_t move_pixels = 3;
    static uint8_t pos;

	LCD_Address_Set(0, 135-20+1, 240, 135);  //设置光标位置 
	for(uint8_t i=0;i<20;i++)
	{ 
        for(uint8_t j=0; j<(LCD_W/8); j++)
        {
            uint8_t temp = pic_ground[i][(pos+j)%40];
            for(uint8_t t=0;t<8;t++)
            {
                if(temp&(0x01<<t))LCD_WR_DATA(BROWN);
                else LCD_WR_DATA(BLACK);
            }
        }
	} 
    pos +=move_pixels;
    if(pos >= 40){
        pos = 0;
    }
}

static void _DrawCloud(uint8_t reset)
{
    const uint8_t move_pixels = 6;
    static int16_t xsta = 240;
    static uint8_t ysta = 0;
    if(reset == 1)
    {
        xsta = 240;
        ysta = 0;
    }

    if(xsta < 0){
        LCD_Address_Set(0, ysta, 72+move_pixels+xsta-1, ysta+21-1);
        uint8_t head_index = (-xsta)/8 ;
        uint8_t first_pixels = (-xsta)%8;
        for(uint8_t i=0;i<21;i++)
        { 
            for(uint8_t j= head_index; j<9; j++)
            {
                if(j == head_index){
                    uint8_t temp = pic_cloud[i][j];
                    for(uint8_t t=first_pixels;t<8;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(WHITE);
                        else LCD_WR_DATA(BLACK);
                    }
                }else{
                    uint8_t temp = pic_cloud[i][j];
                    for(uint8_t t=0;t<8;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(WHITE);
                        else LCD_WR_DATA(BLACK);
                    }
                }
            }
            for(uint8_t i=0; i<move_pixels; i++)
            {
                LCD_WR_DATA(BLACK);
            }
        }   
    }else if((xsta+72-1)>=240){
        LCD_Address_Set(xsta, ysta, 240, ysta+21-1);
        uint8_t tail_index = (240-xsta+1)/8+1;
        uint8_t end_pixels = (240-xsta+1)%8;
        for(uint8_t i=0;i<21;i++)
        { 
            for(uint8_t j= 0; j<tail_index; j++)
            {
                if(j == tail_index-1){
                    uint8_t temp = pic_cloud[i][j];
                    for(uint8_t t=0;t<end_pixels;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(WHITE);
                        else LCD_WR_DATA(BLACK);
                    }
                }else{
                    uint8_t temp = pic_cloud[i][j];
                    for(uint8_t t=0;t<8;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(WHITE);
                        else LCD_WR_DATA(BLACK);
                    }
                }
            }
        }   
    }else{
        LCD_Address_Set(xsta, ysta, xsta+72+move_pixels-1, ysta+21-1);
        for(uint8_t i=0;i<21;i++)
        { 
            for(uint8_t j= 0; j<9; j++)
            {
                uint8_t temp = pic_cloud[i][j];
                for(uint8_t t=0;t<8;t++)
                {
                    if(temp&(0x01<<t))LCD_WR_DATA(WHITE);
                    else LCD_WR_DATA(BLACK);
                }
            }
            for(uint8_t i=0; i<move_pixels; i++)
            {
                LCD_WR_DATA(BLACK);
            }
        }           
    }
    xsta -=move_pixels;
    if((xsta+72-1)<=0){
        xsta = 240;
        LCD_Fill(0,0, move_pixels,50, BLACK); //解决云朵不完全消除bug
        ysta = rand()%25;  //随机高度
    }
}

static uint8_t _DrawCactus(uint8_t reset)
{
    const uint8_t move_pixels = 24;
    static int16_t xsta = 240;
    static uint8_t ysta = 135-40-10;
    static uint8_t pic_select = 0;
    uint8_t temp;

    if(reset == 1)
    {
        xsta = 240;
    }

    if(xsta < 0){
        LCD_Address_Set(0, ysta, 24+move_pixels+xsta-1, ysta+40-1);
        uint8_t head_index = (-xsta)/8 ;
        uint8_t first_pixels = (-xsta)%8;
        for(uint8_t i=0;i<40;i++)
        { 
            for(uint8_t j= head_index; j<3; j++)
            {
                if(pic_select == 0){
                    temp = pic_cactus2[i][j]; 
                }else{
                    temp = pic_cactus1[i][j];
                }
                if(j == head_index){
                    for(uint8_t t=first_pixels;t<8;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(GREEN);
                        else LCD_WR_DATA(BLACK);
                    }
                }else{
                    for(uint8_t t=0;t<8;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(GREEN);
                        else LCD_WR_DATA(BLACK);
                    }
                }
            }
            for(uint8_t i=0; i<move_pixels; i++)
            {
                LCD_WR_DATA(BLACK);
            }
        }   
    }else if((xsta+24-1)>=240){
        LCD_Address_Set(xsta, ysta, 240, ysta+40-1);
        uint8_t tail_index = (240-xsta+1)/8+1;
        uint8_t end_pixels = (240-xsta+1)%8;
        for(uint8_t i=0;i<40;i++)
        { 
            for(uint8_t j= 0; j<tail_index; j++)
            {
                if(pic_select == 0){
                    temp = pic_cactus2[i][j]; 
                }else{
                    temp = pic_cactus1[i][j];
                }
                if(j == tail_index-1){
                    for(uint8_t t=0;t<end_pixels;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(GREEN);
                        else LCD_WR_DATA(BLACK);
                    }
                }else{
                    for(uint8_t t=0;t<8;t++)
                    {
                        if(temp&(0x01<<t))LCD_WR_DATA(GREEN);
                        else LCD_WR_DATA(BLACK);
                    }
                }
            }
        }   
    }else{
        LCD_Address_Set(xsta, ysta, xsta+24+move_pixels-1, ysta+40-1);
        for(uint8_t i=0;i<40;i++)
        { 
            for(uint8_t j= 0; j<3; j++)
            {
                if(pic_select == 0){
                    temp = pic_cactus2[i][j]; 
                }else{
                    temp = pic_cactus1[i][j];
                }
                for(uint8_t t=0;t<8;t++)
                {
                    if(temp&(0x01<<t))LCD_WR_DATA(GREEN);
                    else LCD_WR_DATA(BLACK);
                }
            }
            for(uint8_t i=0; i<move_pixels; i++)
            {
                LCD_WR_DATA(BLACK);
            }
        }           
    }

    uint8_t re_pos = xsta;
    xsta -=move_pixels;
    if((xsta+24-1)<0){
        xsta = 240;
        pic_select++;
        pic_select %=2;
        LCD_Fill(0,50, move_pixels,120, BLACK); //解决云朵不完全消除bug
    }
    return re_pos;
}

static void _DrawDinoRun(void)
{
    const uint8_t offset_x = 20;
    const uint8_t offset_y = 135-20-35+1;
    const uint8_t run_delay = 6;
    static uint8_t run_flag=0;
    LCD_Address_Set(offset_x, offset_y, offset_x+32-1, offset_y+35-1);
    switch (run_flag)
    {
    case run_delay/2:
        for(uint8_t i=0;i<35;i++)
        { 
            for(uint8_t j= 0; j<4; j++)
            {
                uint8_t temp = pic_dino_run1[i][j];
                for(uint8_t t=0;t<8;t++)
                {
                    if(temp&(0x01<<t))LCD_WR_DATA(RED);
                    else LCD_WR_DATA(BLACK);
                }
            }
        }  
        // run_flag = 1;
        break;
    case run_delay:
        for(uint8_t i=0;i<35;i++)
        { 
            for(uint8_t j= 0; j<4; j++)
            {
                uint8_t temp = pic_dino_run2[i][j];
                for(uint8_t t=0;t<8;t++)
                {
                    if(temp&(0x01<<t))LCD_WR_DATA(RED);
                    else LCD_WR_DATA(BLACK);
                }
            }
        }
        // run_flag = 0;  
        break;
    
    default:
        break;
    }

    run_flag++;
    if(run_flag>run_delay){
        run_flag=0;
    }
}

static uint8_t _DrawDinoJump(uint8_t reset)
{
    const uint8_t offset_x = 20;
    const uint8_t offset_y = 135-20-35+1;

	char speed_arr[] = {6,12, 18,24};  //65
	static uint8_t speed_idx = sizeof(speed_arr)-1;
	static int height = 0;
	static uint8_t dir = 0;

    uint8_t last_height = height;

	if(reset == 1)
	{
		height = 0;
		dir = 0;
		speed_idx = sizeof(speed_arr)-1;
		return 0;
	}
	if (dir==0)
	{
		height += speed_arr[speed_idx];
        if(speed_idx <=0){
            dir =1;
        }else{
            speed_idx --;
        }
	}
	else if (dir==1)
	{
		height -= speed_arr[speed_idx];
		if (speed_idx>=sizeof(speed_arr)-1){
            dir = 0;
        }else{
            speed_idx ++;
        }
	}

    
    LCD_Fill(offset_x, offset_y-last_height, offset_x+32, offset_y-last_height+35, BLACK); //清除上一帧图像
    LCD_Address_Set(offset_x, offset_y-height, offset_x+32-1, offset_y-height+35-1);
    for(uint8_t i=0;i<35;i++)
    { 
        for(uint8_t j= 0; j<4; j++)
        {
            uint8_t temp = pic_dino_jump[i][j];
            for(uint8_t t=0;t<8;t++)
            {
                if(temp&(0x01<<t))LCD_WR_DATA(RED);
                else LCD_WR_DATA(BLACK);
            }
        }
    }  

    return height;
}

//应当在不延时循环中调用
void DPM_DinoGame(uint8_t cmd)
{
    const uint8_t score_div = 10;
    static uint8_t dino_height=0;
    static uint32_t game_score =0;
    static uint8_t game_over_flag = 0;
    static uint32_t delay_us =80*1000; //60 ms
    int16_t cactus_pos = 0;
    if(cmd == GAME_RESET){
        LCD_Fill(0, 0, 240, 135, BLACK);
        _DrawCloud(1);
        _DrawCactus(1);
        _DrawDinoJump(1);
        dino_height = 0;
        game_score = 0;
        game_over_flag = 0;
        delay_us = 80*1000;
    }
    if(game_over_flag){  //游戏失败上锁，复位后游戏重启继续
        return;
    }

    _DrawGround();
    _DrawCloud(0);
    cactus_pos = _DrawCactus(0);

    if((cmd == DINO_JUMP) || dino_height>0){
        dino_height = _DrawDinoJump(0);
    }else{
        _DrawDinoRun();
    }

    if(dino_height <30){
        if(cactus_pos>20 && cactus_pos<52){
            game_over_flag =1;
        }else if((cactus_pos+24)>20 && (cactus_pos+24)<52){
            game_over_flag = 1;
        }
    }

    if(game_over_flag){
        LCD_ShowString(84,15, "score:", YELLOW, BLACK, 24,0);
        LCD_ShowIntNum(88, 51, game_score/score_div, 3, RED, BLACK, 32);

        _AddNewScore(game_score/score_div);
    }else{
        game_score++;
        if(delay_us>100){  //时间下限10ms
            delay_us -=100;
        }
        LCD_ShowIntNum(215, 0, game_score/score_div, 3, RED, BLACK, 12);       
    }

    SysTick_Delay_Us(delay_us);
    // SysTick_Delay_Ms(50);
}

void DPM_ShowScoreRecords(void)
{
    LCD_Fill(0,0, 240,135, BLACK);
    _ScoreRead(SCORE_NUM);

    LCD_ShowString(0, 0, "highest:", WHITE, BLACK,24, 0);
    LCD_ShowIntNum(100,0, score_records[SCORE_NUM-1],3, RED, BLACK,24);

    LCD_ShowString(0, 30, "lately:", WHITE, BLACK, 24, 0);
    for(uint8_t i =0; i<SCORE_NUM-1; i++)
    {
        LCD_ShowIntNum(i*32, 60, score_records[i],3, RED, BLACK,16);
    }
}

